package com.neusoft.hifly.message.msg.service.impl;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.neusoft.hifly.commons.lang.StringConstants;
import com.neusoft.hifly.core.basic.service.impl.CTSaaSBaseServiceImpl;
import com.neusoft.hifly.core.log.Log;
import com.neusoft.hifly.core.log.annotation.LogType;
import com.neusoft.hifly.core.log.annotation.OperationLog;
import com.neusoft.hifly.core.token.TokenContextHolder;
import com.neusoft.hifly.core.utils.GlobalConstants;
import com.neusoft.hifly.dynamicds.multi.annotation.MultiDynamicRoutingDataSource;
import com.neusoft.hifly.message.msg.api.domain.ReceiveUserVO;
import com.neusoft.hifly.message.msg.dao.IMsgInboxDao;
import com.neusoft.hifly.message.msg.entity.MsgInboxObj;
import com.neusoft.hifly.message.msg.entity.MsgObj;
import com.neusoft.hifly.message.msg.service.IMsgInboxService;
import com.neusoft.hifly.rpc.email.domain.MailDTO;
import com.neusoft.hifly.rpc.mobile.domain.PushMobileVO;
import com.neusoft.hifly.rpc.sms.domain.SMSToDoDTO;

/**
 * Title: 消息服务
 * <p>
 * Description: 收件箱 Service
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
@Service
@MultiDynamicRoutingDataSource
public class MsgInboxServiceImpl extends CTSaaSBaseServiceImpl implements IMsgInboxService {
	@Autowired(required = false)
	private IMsgInboxDao msgInboxDao;
	@Autowired(required = false)
	private ApplicationContext context;

	/**
	 * 保存个人消息 当起草消息保存后，根据接收人、接收人ID创建个人消息记录
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param receiveUsers
	 *            接收人
	 * @param msgObj
	 *            父消息对象
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void saveMsgboxHave(final String organCode, final long organLogicId, final List<ReceiveUserVO> receiveUsers,
			final MsgObj msgObj) {
		if (receiveUsers == null || receiveUsers.isEmpty() || StringUtils.isEmpty(organCode) || msgObj == null) {
			return;
		}

		MsgInboxObj obj = null;
		for (final ReceiveUserVO user : receiveUsers) {

			// 创建个人消息
			obj = new MsgInboxObj();
			// 父消息逻辑ID
			obj.setMsgLogicId(msgObj.getLogicId());
			// 消息状态(默认未读)
			obj.setMsgStatus(StringConstants.NO);
			// 接收人
			obj.setUserName(user.getUserName());
			// 接收人ID
			obj.setUserId(user.getUserId());

			obj.setMsgType(msgObj.getType());
			obj.setObjId(msgObj.getObjId());
			saveOrUpdate(organCode, organLogicId, obj);

			sendMsg(msgObj, organCode, organLogicId, obj, msgObj.getUserName(), user);
		}
	}

	/**
	 * 发送信息
	 *
	 * @param msgObj
	 *            信息
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param obj
	 *            收件箱
	 * @param sendUserName
	 *            发件人姓名
	 * @param receiveUser
	 *            收件人
	 */
	private void sendMsg(final MsgObj msgObj, final String organCode, final long organLogicId, final MsgInboxObj obj,
			final String sendUserName, final ReceiveUserVO receiveUser) {

		/* 短消息（手机APP推送） */
		if (msgObj.getSendType().indexOf(MsgObj.SENDTYPE_IM) >= 0) {
			/* 发送手机App */
			context.publishEvent(new PushMobileVO(msgObj.getTitle(), msgObj.getContent(), receiveUser.getUserId(),
					receiveUser.getUserId(), null));
		}

		/* 邮件 */
		if (msgObj.getSendType().indexOf(MsgObj.SENDTYPE_EMAIL) >= 0) {
			final MailDTO mail = new MailDTO();
			mail.setTitle(msgObj.getTitle());
			mail.setContent(msgObj.getContent());
			mail.setEmail(receiveUser.getEmail());
			context.publishEvent(mail);
		}

		/* 短信 */
		if (msgObj.getSendType().indexOf(MsgObj.SENDTYPE_SMS) >= 0) {
			context.publishEvent(
					new SMSToDoDTO(organLogicId, sendUserName, receiveUser.getMobile(), msgObj.getContent()));
		}

		/* 钉钉 */
		if (msgObj.getSendType().indexOf(MsgObj.SENDTYPE_DINGDING) >= 0) {
			try {
				Log.error("TODO 发送钉钉...暂时未实现");
			} catch (final Exception e) {
				Log.error("发送信息失败!" + e.getMessage());
			}
		}
	}

	/**
	 * 保存对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param obj
	 *            对象
	 */
	@Override
	@OperationLog(method = LogType.UPDATE, msg = "收件箱")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void saveOrUpdate(final String organCode, final long organLogicId, final MsgInboxObj obj) {
		if (StringUtils.isEmpty(organCode) || obj == null) {
			return;
		}

		final MsgInboxObj oldObj = msgInboxDao.getByLogicId(organCode, organLogicId, obj.getLogicId());

		obj.setOrganLogicId(organLogicId);

		// 有ID的话要判断是否保存还是更新
		if (oldObj == null) {
			// 保存
			obj.setId(idWorker.nextId());
			if (GlobalConstants.ABS_ID != obj.getLogicId()) {
				obj.setLogicId(idWorker.nextId());
			}
			obj.setUpdateTime(LocalDateTime.now());

			if (StringUtils.isEmpty(obj.getUpdatePerson())) {
				obj.setUpdatePerson(TokenContextHolder.get().getUserName());
			}

			this.setForm(obj, obj);

			msgInboxDao.insert(obj);

		} else {
			// 更新

			this.setForm(obj, oldObj);

			oldObj.setUpdateTime(LocalDateTime.now());
			if (StringUtils.isEmpty(oldObj.getUpdatePerson())) {
				oldObj.setUpdatePerson(TokenContextHolder.get().getUserName());
			}

			msgInboxDao.updateById(oldObj);

		}
	}

	/**
	 * 单条消息已读
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param logicId
	 *            逻辑ID
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void updateIsRead(final String organCode, final long organLogicId, final long logicId) {
		if (StringUtils.isEmpty(organCode)) {
			return;
		}
		msgInboxDao.updateIsRead(organCode, organLogicId, logicId, LocalDateTime.now());
	}

	/**
	 * 全部消息已读
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param receiveUserLogicId
	 *            接收人
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void updateAllIsRead(final String organCode, final long organLogicId, final long receiveUserLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return;
		}
		msgInboxDao.updateAllIsRead(organCode, organLogicId, receiveUserLogicId, LocalDateTime.now());
	}

	/**
	 * 根据ID删除对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param logicId
	 *            对象ID
	 */
	@Override
	@OperationLog(method = LogType.DELETE, msg = "收件箱")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void deleteByLogicId(final String organCode, final long organLogicId, final long logicId) {
		if (StringUtils.isEmpty(organCode)) {
			return;
		}

		msgInboxDao.deleteByLogicId(organCode, organLogicId, logicId);

	}

	/**
	 * 批量删除对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param logicIds
	 *            对象ID，多id使用英文逗号分隔
	 */
	@Override
	public void deleteByBatch(final String organCode, final long organLogicId, final String logicIds) {
		if (StringUtils.isEmpty(organCode) || StringUtils.isEmpty(logicIds)) {
			return;
		}
		final String[] logicIdArr = logicIds.split(StringConstants.STRING_SPLIT_FLAG_3);
		if (logicIdArr == null) {
			return;
		}
		for (final String logicId : logicIdArr) {
			if (StringUtils.isEmpty(logicId)) {
				continue;
			}
			this.deleteByLogicId(organCode, organLogicId, Long.parseLong(logicId));
		}
	}

	/**
	 * 删除对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param objLogicId
	 *            业务表单的ID
	 */
	@Override
	@OperationLog(method = LogType.DELETE, msg = "收件箱")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void deleteByObjLogicId(final String organCode, final long organLogicId, final long objLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return;
		}
		msgInboxDao.deleteByObjLogicId(organCode, organLogicId, objLogicId);
	}

	/**
	 * 删除对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param msgLogicId
	 *            父消息逻辑ID
	 */
	@Override
	@OperationLog(method = LogType.DELETE, msg = "收件箱")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public void deleteByMsgLogicId(final String organCode, final long organLogicId, final long msgLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return;
		}
		msgInboxDao.deleteByMsgLogicId(organCode, organLogicId, msgLogicId);
	}

	/**
	 * 统计未读信息数量
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户ID
	 * @param userLogicId
	 *            用户ID
	 * @return 数量
	 */
	@Override
	public int countAllUnread(final String organCode, final long organLogicId, final long userLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return 0;
		}
		return msgInboxDao.countAllUnread(organCode, organLogicId, userLogicId);
	}

	/**
	 * 根据id查询对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param logicId
	 *            对象logicId
	 * @return 对象
	 */
	@Override
	public MsgInboxObj getByLogicId(final String organCode, final long organLogicId, final long logicId) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		return msgInboxDao.getByLogicId(organCode, organLogicId, logicId);
	}

	/**
	 * 查询所有对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @return 对象集合
	 */
	@Override
	public List<MsgInboxObj> findAll(final String organCode, final long organLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		return msgInboxDao.findAll(organCode, organLogicId);
	}

	/**
	 * 查询所有对象
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param msgLogicId
	 *            父消息逻辑ID
	 * @return 对象集合
	 */
	@Override
	public List<MsgInboxObj> findByMsgLogicId(final String organCode, final long organLogicId, final long msgLogicId) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		return msgInboxDao.findByMsgLogicId(organCode, organLogicId, msgLogicId);
	}

	/**
	 * 根据条件查询
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param property
	 *            参数。其中isLike:Boolean 是否模糊查询
	 * @return 集合
	 */
	@Override
	public List<MsgInboxObj> search(final String organCode, final long organLogicId, Map<String, Object> property) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		if (property == null) {
			property = new HashMap<String, Object>(1);
			property.put("organLogicId", organLogicId);
		}
		final QueryWrapper<MsgInboxObj> queryWrapper = new QueryWrapper<MsgInboxObj>();
		replaceProperty(property);
		createSql(property, queryWrapper);

		queryWrapper.orderBy(true, true, "MSG_STATUS");
		queryWrapper.orderBy(true, false, "RECEIVE_TIME");

		return msgInboxDao.selectList(queryWrapper);
	}

	/**
	 * 根据条件查询
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param offset
	 *            当前页数
	 * @param limit
	 *            分页长度
	 * @param property
	 *            参数。其中isLike:Boolean 是否模糊查询
	 * @return 返回Map
	 */
	@Override
	public IPage<MsgInboxObj> search(final String organCode, final long organLogicId, final int offset, final int limit,
			Map<String, Object> property) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		if (property == null) {
			property = new HashMap<String, Object>(1);
			property.put("organLogicId", organLogicId);
		}
		final IPage<MsgInboxObj> page = new Page<MsgInboxObj>(offset, limit);
		final QueryWrapper<MsgInboxObj> queryWrapper = new QueryWrapper<MsgInboxObj>();
		replaceProperty(property);
		createSql(property, queryWrapper);

		queryWrapper.orderBy(true, true, "MSG_STATUS");
		queryWrapper.orderBy(true, false, "RECEIVE_TIME");

		return msgInboxDao.selectPage(page, queryWrapper);
	}

	/**
	 * 搜索未读消息
	 *
	 * @param organCode
	 *            租户编码
	 * @param organLogicId
	 *            租户逻辑ID
	 * @param offset
	 *            当前页数
	 * @param limit
	 *            分页长度
	 * @param property
	 *            参数。其中isLike:Boolean 是否模糊查询
	 * @return 返回Map
	 */
	@Override
	public Map<String, Object> searchHaveMsg(final String organCode, final long organLogicId, final int offset,
			final int limit, Map<String, Object> property) {
		if (StringUtils.isEmpty(organCode)) {
			return null;
		}
		if (property == null) {
			property = new HashMap<String, Object>(1);
			property.put("organLogicId", organLogicId);
		}
		final com.baomidou.mybatisplus.plugins.Page<MsgInboxObj> page = new com.baomidou.mybatisplus.plugins.Page<MsgInboxObj>(
				offset, limit);

		final Map<String, Object> map = new HashMap<String, Object>(2);
		map.put(GlobalConstants.PAGE_RESULTS, msgInboxDao.searchHaveMsg(organCode, organLogicId, page, property));
		map.put(GlobalConstants.PAGE_COUNT, msgInboxDao.countHaveMsg(organCode, organLogicId, property));
		return map;
	}

	/**
	 * 复制信息
	 *
	 * @param fromObj
	 *            原信息
	 * @param toObj
	 *            新信息
	 */
	private void setForm(final MsgInboxObj fromObj, final MsgInboxObj toObj) {
		toObj.setOrganLogicId(fromObj.getOrganLogicId());
		toObj.setMsgLogicId(fromObj.getMsgLogicId());
		toObj.setMsgStatus(StringUtils.trimToEmpty(fromObj.getMsgStatus()));
		toObj.setUserId(fromObj.getUserId());
		toObj.setUserName(StringUtils.trimToEmpty(fromObj.getUserName()));
		toObj.setReceiveTime(fromObj.getReceiveTime());
		toObj.setMsgType(StringUtils.trimToEmpty(fromObj.getMsgType()));
		toObj.setObjId(fromObj.getObjId());
		toObj.setSysCode(StringUtils.trimToEmpty(fromObj.getSysCode()));
		toObj.setExt1(StringUtils.trimToEmpty(fromObj.getExt1()));
		toObj.setExt2(StringUtils.trimToEmpty(fromObj.getExt2()));
		toObj.setExt3(StringUtils.trimToEmpty(fromObj.getExt3()));
		toObj.setExt4(StringUtils.trimToEmpty(fromObj.getExt4()));
		toObj.setExt5(StringUtils.trimToEmpty(fromObj.getExt5()));

	}

	/**
	 * 将对象属性替换成数据库列
	 *
	 * @param property
	 *            参数
	 */
	private void replaceProperty(final Map<String, Object> property) {
		if (property != null) {
			if (property.containsKey("organLogicId")) {
				property.put("ORGAN_LOGIC_ID", property.get("organLogicId"));
				property.remove("organLogicId");
			}
			if (property.containsKey("msgLogicId")) {
				property.put("MSG_LOGIC_ID", property.get("msgLogicId"));
				property.remove("msgLogicId");
			}
			if (property.containsKey("msgStatus")) {
				property.put("MSG_STATUS", property.get("msgStatus"));
				property.remove("msgStatus");
			}
			if (property.containsKey("userId")) {
				property.put("USER_ID", property.get("userId"));
				property.remove("userId");
			}
			if (property.containsKey("userName")) {
				property.put("USER_NAME", property.get("userName"));
				property.remove("userName");
			}
			if (property.containsKey("receiveTime")) {
				property.put("RECEIVE_TIME", property.get("receiveTime"));
				property.remove("receiveTime");
			}
			if (property.containsKey("msgType")) {
				property.put("MSG_TYPE", property.get("msgType"));
				property.remove("msgType");
			}
			if (property.containsKey("objId")) {
				property.put("OBJ_ID", property.get("objId"));
				property.remove("objId");
			}
			if (property.containsKey("sysCode")) {
				property.put("SYS_CODE", property.get("sysCode"));
				property.remove("sysCode");
			}
			if (property.containsKey("updatePerson")) {
				property.put("UPDATE_PERSON", property.get("updatePerson"));
				property.remove("updatePerson");
			}
			if (property.containsKey("updateTime")) {
				property.put("UPDATE_TIME", property.get("updateTime"));
				property.remove("updateTime");
			}
			if (property.containsKey("ext1")) {
				property.put("EXT1", property.get("ext1"));
				property.remove("ext1");
			}
			if (property.containsKey("ext2")) {
				property.put("EXT2", property.get("ext2"));
				property.remove("ext2");
			}
			if (property.containsKey("ext3")) {
				property.put("EXT3", property.get("ext3"));
				property.remove("ext3");
			}
			if (property.containsKey("ext4")) {
				property.put("EXT4", property.get("ext4"));
				property.remove("ext4");
			}
			if (property.containsKey("ext5")) {
				property.put("EXT5", property.get("ext5"));
				property.remove("ext5");
			}

		}
	}
}